##
#
# Snaarpy: Guitar chord parser and formatter
# Copyright (C) 2009 Alberto Gonzalez
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
##

from snaarpy.input import InputFileReader
from snaarpy.model import *
from snaarpy.chordutils import chord_frets

import logging
logger = logging.getLogger(__name__)

import re, codecs

CHORD_R = r'[A-G][b#]?[bmajindsu0-9]*(?:/[A-G][b#]?)?'
chord_p = re.compile(CHORD_R)

IS_CHORDLINE_R = r'^\s*(?:%s\s*)+$' % CHORD_R
is_chordline_p = re.compile(IS_CHORDLINE_R)

def is_chord_line(line):
    if is_chordline_p.match(line):
        return True
    return False

def get_chords(line):
    res = []
    for m in chord_p.finditer(line):
        res.append((m.start(), m.group(0)))
    return res

def could_be_tab(input):
    if len(input) < 6: return False
    if any(l == '' for l in input[0:6]): return False

class TextFileReader(InputFileReader):
    extension = "txt"
    description = "Plain ASCII text file input filter"

    def read(self):
        song = Song()
        
        input = []
        for line in codecs.open(self.file_path, 'r', 'utf-8'):
            input.append(line.rstrip())
        while len(input):
            if input[0][0:3] == '#!!':
                line = input.pop(0)
                raw = line[3:].split(None, 1)
                cmd = raw[0]
                if len(raw) > 1:
                    args = raw[1]
                else:
                    args = None
                try:
                    f = self.__getattribute__('cmd_' + cmd.lower())
                    f(song, args)
                except AttributeError:
                    logger.warning("%s: Ignored command '%s'" % (self.file_path, cmd.lower()))
            elif input[0] == "":
                input.pop(0)
                song.groups.append(Group("Verse"))
            elif is_chord_line(input[0]):
                line = input.pop(0)
                chords = get_chords(line)
                group = song.groups[-1]
                if input[0] == "" or is_chord_line(input[0]):
                    new = Instrumental()
                    for chord in zip(*chords)[1]:
                        if chord in song.chords:
                            ch = song.chords[chord]
                        else:
                            frets = chord_frets(chord)
                            if not frets:
                                logger.warning("%s: Unknown chord '%s'" % (self.file_path, chord))
                            ch = Chord(chord, frets)
                            song.chords[chord] = ch
                        new.chunks.append(ChordUse(ch))
                else:
                    lyrics = input.pop(0)
                    new = Verse()
                    last = 0
                    while len(chords) > 0:
                        pos, chord = chords.pop(0)
                        fragment = lyrics[last:pos]
                        last = pos
                        if fragment:
                            new.chunks.append(Text(fragment))
                        if len(chords) > 0: #there's a next chord
                            max = chords[0][0]
                        else:
                            max = len(lyrics)
                        last, word = self.chord_word(lyrics, last, max)
                        if chord in song.chords:
                            ch = song.chords[chord]
                        else:
                            frets = chord_frets(chord)
                            if not frets:
                                logger.warning("%s: Unknown chord '%s'" % (self.file_path, chord))
                            ch = Chord(chord, frets)
                            song.chords[chord] = ch
                        new.chunks.append(ChordUse(ch, word))
                    if last < len(lyrics):
                        new.chunks.append(Text(lyrics[last:]))
                group.verses.append(new)
            else:
                line = input.pop(0)
                new = Verse()
                new.chunks.append(Text(line))
                group = song.groups[-1]
                group.verses.append(new)
        song.groups = [ g for g in song.groups if len(g.verses) > 0 ]
        return song
    
    def chord_word(self, lyric, last, max):
        pos = lyric.find(' ', last, max)
        if pos == -1:
            pos = max
        return pos, lyric[last:pos]
    
    def cmd_capo(self, song, capo):
        song.capo = capo
    
    def cmd_chord(self, song, chorddef):
        short, frets = chorddef.split(None, 1)
        ch = Chord(short, frets)
        song.chords[short] = ch
    
    def cmd_section(self, song, label):
        song.groups[-1].label = label
    
    def cmd_title(self, song, title):
        song.title = title
        
    def cmd_author(self, song, author):
        song.author = author